'''
引入大智慧导出的自定义数据文件txt,bwwmacd数据导入为data_signals,

买入： 根据里面的m5,利用内置均线公式计算金叉
       附加判断低迷期低于股票总数的75%, 程序设定小于-500 .

止损：  指标多头状态，跌破买入价执行
        macd 小于0, 跌破买入价 1% 否则 3%。

仓位控制：  macd 小于0, 买入1份, 大于0-买入2份
'''
import backtrader as bt  
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt

from backtrader_plotting import Bokeh
from backtrader_plotting.schemes import Tradimo

import csv

from data_feed import data_dzh, stock_zh_index_daily, MyStockData, MySignalData
from MyStrategy import MyStrategy

symbol="sh000001"
filename='macd.txt'

# 获取上证指数的历史行情数据  
data_stock = stock_zh_index_daily(symbol=symbol)
data_stock = data_stock.get_data()

# 获取大智慧自定义文件
filename='macd.txt'
bwwmacd_file_path = f'法宝回测/dzh自定义/{filename}'  # 替换为你的文件路径
data_bwwmacd = data_dzh(bwwmacd_file_path)
data_bwwmacd = data_bwwmacd.read_and_convert_txt_to_dataframe()
    

#============== 创建Cerebro引擎========================================
# 创建Cerebro引擎  
cerebro = bt.Cerebro()  

# 设置回测时间范围
start_date = datetime(2023, 5, 1)
end_date = datetime.now()

# =============添加数据源  ==============
datafeed_stock = MyStockData(dataname=data_stock, fromdate=start_date, todate=end_date)  
datafeed_signal = MySignalData(dataname=data_bwwmacd, fromdate=start_date, todate=end_date)  

# 将数据源添加到cerebro ，一定要加name=......, 否则出不了图
cerebro.adddata(datafeed_stock, name=symbol)  
cerebro.adddata(datafeed_signal, name=filename)  

# ============添加策略  ============
cerebro.addstrategy(MyStrategy)  
# =============================================================
# 设置初始资金和手续费
start_cash = 1000000
cerebro.broker.setcash(start_cash)
cerebro.broker.setcommission(commission=0.002)

# 添加策略分析指标
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='tradeanalyzer')  
cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annualReturn')  
cerebro.addanalyzer(bt.analyzers.Returns, _name='annualizedReturns', tann=252)  # 使用 'annualizedReturns' 代替 '_Returns'  
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')  
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpeRatio')  # 使用 'sharpeRatio' 代替 'sharpe'  
cerebro.addanalyzer(bt.analyzers.Returns, _name='totalReturns')  # 使用 'totalReturns' 代替重复的 'returns'  
# 假设 'TimeReturn' 是有效的分析器  
cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='timeReturn')  # 假设这是有效的

# 运行回测==========================
results = cerebro.run()

#=====================================#获取回测结果并打印========================
port_value = cerebro.broker.getvalue()
pnl = port_value - start_cash
print(f"初始资金: {start_cash}\n回测期间：{start_date.strftime('%Y%m%d')}:{end_date.strftime('%Y%m%d')}")
print(f"总资金: {round(port_value, 2)}")
print(f"净收益: {round(pnl, 2)}")#计算胜率
total_trades = results[0].analyzers.tradeanalyzer.get_analysis()['total']['total']
won_trades = results[0].analyzers.tradeanalyzer.get_analysis()['won']['total']
win_rate = (won_trades / total_trades) * 100 if total_trades > 0 else 0
print('总交易次数:', total_trades)
print('盈利次数:', won_trades)
print('胜率%:', win_rate)

print('年化收益%:', results[0].analyzers.annualizedReturns.get_analysis()['rnorm100'])
print('最大回撤比例%:', results[0].analyzers.drawdown.get_analysis().max.drawdown)
print('夏普比率:', results[0].analyzers.sharpeRatio.get_analysis()['sharperatio'])
print('累计收益：', results[0].analyzers.totalReturns.get_analysis()['rtot'])

print(f'最后投资金额：{round(cerebro.broker.getvalue(), 2)}')

#=========================================================================================

# 获取分析结果
port_value = cerebro.broker.getvalue()
pnl = port_value - start_cash
total_trades = results[0].analyzers.tradeanalyzer.get_analysis()['total']['total']
won_trades = results[0].analyzers.tradeanalyzer.get_analysis()['won']['total']
win_rate = (won_trades / total_trades) * 100 if total_trades > 0 else 0
annualized_return = results[0].analyzers.annualizedReturns.get_analysis()['rnorm100']
max_drawdown = results[0].analyzers.drawdown.get_analysis().max.drawdown
sharpe_ratio = results[0].analyzers.sharpeRatio.get_analysis()['sharperatio']
cumulative_return = results[0].analyzers.totalReturns.get_analysis()['rtot']

# 创建一个包含所有结果的列表
results_list = [
    ["初始资金", start_cash],
    ["回测期间", f"{start_date.strftime('%Y%m%d')}:{end_date.strftime('%Y%m%d')}"],
    ["总资金", round(port_value, 2)],
    ["净收益", round(pnl, 2)],
    ["总交易次数", total_trades],
    ["盈利次数", won_trades],
    ["胜率%", win_rate],
    ["年化收益%", annualized_return],
    ["最大回撤比例%", max_drawdown],
    ["夏普比率", sharpe_ratio],
    ["累计收益", cumulative_return],
    ["最后投资金额", round(cerebro.broker.getvalue(), 2)]
]

# # 将结果写入CSV文件
# with open('法宝回测\\dzh自定义\\results.csv', 'w', newline='', encoding='utf-8') as file:
#     writer = csv.writer(file)
#     writer.writerow(["指标", "值"])
#     writer.writerows(results_list)
# print("结果已成功写入 results.csv 文件")

# 将结果转换为DataFrame
df_results = pd.DataFrame(results_list, columns=["指标", "值"])

# 将DataFrame保存为Excel文件
df_results.to_excel('法宝回测\\dzh自定义\\results.xlsx', index=False)

print("结果已成功写入 results.xlsx 文件")

#=====================================================================================

# 获取策略实例
strategy_instance = results[0]

# 调用策略实例的get_print_list方法获取print_list
# 调出成交列表
print_list = strategy_instance.get_print_list()


def parse_data_strings_to_df(data_strings):  # 成交列表转成dataframe
    data_rows = []  
    for data_str in data_strings:  
        parts = data_str.split(',')  # 按逗号分割字符串  
        row_data = {}  
        for part in parts:  
            key_value = part.split(':')  # 尝试按冒号分割键值对  
            if len(key_value) == 2:  
                key, value = key_value  
                row_data[key.strip()] = value.strip()  # 去除键和值两侧的空白字符  
            else:  
                print(f"Warning: Invalid key-value pair: {part}")  
        data_rows.append(row_data)  
    return pd.DataFrame(data_rows)  
  
# 创建一个DataFrame  
df_print_list = parse_data_strings_to_df(print_list) 
# df.to_csv('法宝回测\dzh自定义\print_list.csv', index=False)

# 将DataFrame保存为Excel文件
df_print_list.to_excel('法宝回测\dzh自定义\print_list.xlsx', index=False)
# 打印DataFrame查看结果  
print(df_print_list)

print("结果已成功写入 print_list 文件")

#=====================================================
# 使用 ExcelWriter 将两个 DataFrame 写入同一个 Excel 文件的不同工作表
with pd.ExcelWriter('法宝回测\\dzh自定义\\combined_results1.xlsx') as writer:
    df_results.to_excel(writer, sheet_name='分析结果', index=False)
    df_print_list.to_excel(writer, sheet_name='打印列表', index=False)

print("结果已成功写入 combined_results1.xlsx 文件")
# ==============================================================

# 将两个 DataFrame 并排合并成一个 DataFrame
df_combined = pd.concat([df_print_list, df_results], axis=1)

# 将合并后的 DataFrame 保存为 Excel 文件
df_combined.to_excel('法宝回测\\dzh自定义\\combined_results2.xlsx', index=False)

print("结果已成功写入 combined_results2.xlsx 文件")

#====================================出图==============================================
plotconfig = {
    'id:ind#0': dict(
        subplot=True,
    ),
}
b = Bokeh(style='line', scheme=Tradimo(),plotconfig=plotconfig)
cerebro.plot(b)